/**
 * @file STL_Async.h
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 0.1
 * @date 2021-05-15
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2021
 * 
 */

#ifndef __STL_ASYNC_H__
#define __STL_ASYNC_H__

#include <future>
#include <list>
#include <chrono> //计时器
#include <mutex>
#include <time.h>

#include "STL_ModLog.h"

// std::async(launch policy, Fn&& fn, Args&&... args)
//
// launch policy 启动策略
// std::launch::async 构造时起线程执行函数，通过wait_for可以测试执行完成状态 ，完成后结果通过get获取
// std::launch::deferred 构造时不执行函数，当执行get时，同步执行函数返回执行结果

#define STL_ASYNC(func, args...)                             \
    do                                                       \
    {                                                        \
        std::future<void> *fut = new std::future<void>();    \
        *fut = std::async(std::launch::async, func, ##args); \
        STL::STL_Async::getInstance()->addFuture(fut);       \
    } while (0)

#define STL_ASYNC_TIMEOUT(name, timeout, func, args...)               \
    do                                                                \
    {                                                                 \
        std::future<void> *fut = new std::future<void>();             \
        *fut = std::async(std::launch::async, func, ##args);          \
        STL::STL_Async::getInstance()->addFuture(fut, name, timeout); \
    } while (0)

namespace STL
{
    class STL_Async : public STL_ModLog
    {
    private:
        typedef struct CheckFuture_t
        {
            std::string name;
            long timeout;
            std::future<void> *pFut;
        } CheckFuture;

    private:
        STL_Async() : STL_ModLog("STL_Async")
        {
            std::future<void> *fut = new std::future<void>();
            *fut = std::async(std::launch::async, [this]()
                              {
                                  while (1)
                                  {
                                      checkFuture();
                                      std::this_thread::sleep_for(std::chrono::milliseconds(10));
                                  }
                              });
            addFuture(fut);
        };
        ~STL_Async() = default;

    public:
        static STL_Async *getInstance()
        {
            static STL_Async instance;
            return &instance;
        };

    public:
        void addFuture(std::future<void> *pFut, std::string name = "", long timeout = -1)
        {
            CheckFuture cf;
            cf.name = name;
            cf.timeout = -1;
            if (timeout > 0)
                cf.timeout = time(NULL) + timeout;
            cf.pFut = pFut;
            std::lock_guard<std::mutex> guard(m_futListMutex);
            m_futList.push_back(cf);
        };

        void checkFuture()
        {
            std::lock_guard<std::mutex> guard(m_futListMutex);
            // int i = 0;
            // printf("checkFuture @@-------\n");
            for (auto it = m_futList.begin(); it != m_futList.end();)
            {
                // i++;
                auto ite = it++;
                auto status = ite->pFut->wait_for(std::chrono::nanoseconds(1)); //FIXME 崩溃点
                if (status == std::future_status::timeout)
                {
                    if (ite->timeout > 0)
                    {
                        long timeout = time(NULL) - ite->timeout;
                        if (timeout > 0)
                        {
                            modlog_warn("[%s] 这个傻逼进程已经超时了，有人管没有啊?\n", ite->name.c_str());
                            ite->timeout = -1;
                        }
                        // printf("[%s]wait_for timeout[%ld]\n", ite->name.c_str(), timeout);
                    }
                }
                else if (status == std::future_status::ready)
                {
                    // printf("[%d]wait_for ready\n", i);
                    ite->pFut->get();
                    m_futList.erase(ite);
                }
                else //future_status::deferred
                {
                    // printf("[%d]wait_for deferred\n", i);
                }
            }
            // printf("checkFuture ##-------\n");
        }

    private:
        std::mutex m_futListMutex;
        std::list<CheckFuture> m_futList;
    };
} // namespace STL

#endif //__STL_ASYNC_H__
